<?php
namespace Ktadmin\Ali;

use think\facade\Db;
use app\base\model\BaseModel;
use think\facade\Cache;

use AlibabaCloud\Client\AlibabaCloud;
use AlibabaCloud\Client\Exception\ClientException;
use AlibabaCloud\Client\Exception\ServerException;

/**
* 阿里智能语音合成
*/
class Ai
{
	protected $AccessKeyID;
	protected $AccessKeySecret;
	protected $appkey;
	protected $region;
	protected $token;
	protected $format = "mp3";
	protected $sampleRate = 16000;
	protected $audioSaveFile;

    public function __construct($AccessKeyID,$AccessKeySecret,$appkey,$region='cn-shanghai'){
		$this->AccessKeyID = $AccessKeyID;
		$this->AccessKeySecret = $AccessKeySecret;
		$this->appkey = $appkey;
		$this->region = $region;
	}

	function processGETRequest($text, $audioSaveFile="", $format="", $sampleRate="",$voice="xiaoyun") {
		$token = $this->getalyuntoken($this->AccessKeyID,$this->AccessKeySecret);
		$format = $format ?: $this->format;
		$audioSaveFile = $audioSaveFile ?: root_path().'public/static/tem/storage/aliai/'.time().'_'.rand(1,99).'.'.$format;
		$sampleRate = $sampleRate ?: $this->sampleRate;

		if(!$token) return error('配置错误');
	    $url = "https://nls-gateway-".$this->region.".aliyuncs.com/stream/v1/tts?";
	    $url = $url . "appkey=" . $this->appkey;
	    $url = $url . "&token=" . $token;
	    $url = $url . "&text=" . urlencode($text);
	    $url = $url . "&format=" . $this->format;
	    $url = $url . "&sample_rate=" . strval($sampleRate);
	    // voice 发音人，可选，默认是xiaoyun。
	    $url = $url . "&voice=" . $voice;
	    // volume 音量，范围是0~100，可选，默认50。
	    // $url = $url . "&volume=" . strval(50);
	    // speech_rate 语速，范围是-500~500，可选，默认是0。
	    // $url = $url . "&speech_rate=" . strval(0);
	    // pitch_rate 语调，范围是-500~500，可选，默认是0。
	    // $url = $url . "&pitch_rate=" . strval(0);
	    $curl = curl_init();
	    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
	    /**
	     * 设置HTTPS GET URL。
	     */
	    curl_setopt($curl, CURLOPT_URL, $url);
	    /**
	     * 设置返回的响应包含HTTPS头部信息。
	     */
	    curl_setopt($curl, CURLOPT_HEADER, TRUE);
	    /**
	     * 发送HTTPS GET请求。
	     */
	    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
	    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
	    $response = curl_exec($curl);
	    if ($response == FALSE) {
	        return 'curl_exec failed!';
	        curl_close($curl);
	        return ;
	    }
	    /**
	     * 处理服务端返回的响应。
	     */
	    $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
	    $headers = substr($response, 0, $headerSize);
	    $bodyContent = substr($response, $headerSize);
	    curl_close($curl);
	    if (stripos($headers, "Content-Type: audio/mpeg") != FALSE || stripos($headers, "Content-Type:audio/mpeg") != FALSE) {
	        file_put_contents($audioSaveFile, $bodyContent);
	        return $audioSaveFile;
	    }else {
	    	return "";
	    }
	}
	function processPOSTRequest($text, $audioSaveFile="", $format="", $sampleRate="" ,$voice="xiaoyun") {
		$token = $this->getToken();
	    $url = "https://nls-gateway-".$this->region.".aliyuncs.com/stream/v1/tts";
	    $audioSaveFile = $audioSaveFile ?: root_path().'public/storage/aliai/'.time().'_'.rand(1,99).'.'.$format;
		$format = $format ?: $this->$sampleRate;
		$sampleRate = $sampleRate ?: $this->$sampleRate;
	    /**
	     * 请求参数，以JSON格式字符串填入HTTPS POST请求的Body中。
	     */
	    $taskArr = array(
	        "appkey" => $this->AccessKeyID,
	        "token" => $token,
	        "text" => $text,
	        "format" => $format,
	        "sample_rate" => $sampleRate,
	        // voice 发音人，可选，默认是xiaoyun。
	        "voice" => "xiaoyun",
	        // volume 音量，范围是0~100，可选，默认50。
	        // "volume" => 50,
	        // speech_rate 语速，范围是-500~500，可选，默认是0。
	        // "speech_rate" => 0,
	        // pitch_rate 语调，范围是-500~500，可选，默认是0。
	        // "pitch_rate" => 0
	    );
	    $body = json_encode($taskArr);
	    $curl = curl_init();
	    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
	    /**
	     * 设置HTTPS POST URL。
	     */
	    curl_setopt($curl, CURLOPT_URL, $url);
	    curl_setopt($curl, CURLOPT_POST, TRUE);
	    /**
	     * 设置HTTPS POST请求头部。
	     * */
	    $httpHeaders = array(
	        "Content-Type: application/json"
	    );
	    curl_setopt($curl, CURLOPT_HTTPHEADER, $httpHeaders);
	    /**
	     * 设置HTTPS POST请求体。
	     */
	    curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
	    /**
	     * 设置返回的响应包含HTTPS头部信息。
	     */
	    curl_setopt($curl, CURLOPT_HEADER, TRUE);
	    /**
	     * 发送HTTPS POST请求。
	     */
	    $response = curl_exec($curl);
	    if ($response == FALSE) {
	        curl_close($curl);
	        return error('合成失败');
	    }
	    /**
	     * 处理服务端返回的响应。
	     */
	    $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
	    $headers = substr($response, 0, $headerSize);
	    $bodyContent = substr($response, $headerSize);
	    curl_close($curl);
	    if (stripos($headers, "Content-Type: audio/mpeg") != FALSE || stripos($headers, "Content-Type:audio/mpeg") != FALSE) {
	        file_put_contents($audioSaveFile, $bodyContent);
	        return success('合成成功',$audioSaveFile);
	    }else {
	    	return error("The GET request failed: " . $bodyContent);
	    }
	}
	/**
	 *  获取 Access Token
	 */
	private function getToken()
	{
		if(!$this->AccessKeyID) return false;
		$tokenId = Cache::get($this->AccessKeyID);
		if(!$tokenId){
			$AccessKeyID = $this->AccessKeyID;
			$AccessKeySecret = $this->AccessKeySecret;
			$region = $this->region;
			/**
			 * 第一步：设置一个全局客户端
			 * 使用阿里云RAM账号的AccessKey ID和AccessKey Secret进行鉴权。
			 */
			AlibabaCloud::accessKeyClient($AccessKeyID,$AccessKeySecret)
			            ->regionId($region)
			            ->asDefaultClient();
			try {
			    $response = AlibabaCloud::nlsCloudMeta()
			                            ->v20180518()
			                            ->createToken()
			                            ->request();
			   	
			    $token = $response["Token"];
			    if ($token != NULL) {
			    	$tokenId = $token["Id"];
			    	$ExpireTime = $token["ExpireTime"] - time();
			    	Cache::set($this->AccessKeyID,$tokenId,$ExpireTime);
			    }
			    else {
			        return '';
			    }
			} catch (ClientException $exception) {
			    // 获取错误消息
			   echo 1;die;
			    return error($exception->getErrorMessage());
			    return '';
			} catch (ServerException $exception) {
			    // 获取错误消息
			     echo 2;die;
			     return error($exception->getErrorMessage());
				return '';
			}
		}

        return $tokenId;
	}

	public function getalyuntoken($accesskeyid,$accessKeysecret){
		$token = Cache::get($accesskeyid);
		if(!$token){
			date_default_timezone_set("Etc/GMT");
			$one = md5(time());
			$parms = array("AccessKeyId" => $accesskeyid,"Action" => "CreateToken","Version" => "2019-02-28","Format" => "JSON","RegionId" => "cn-shanghai","Timestamp" => date("Y-m-d\TH:i:s\Z"),"SignatureMethod" => "HMAC-SHA1","SignatureVersion" => "1.0","SignatureNonce" => substr($one,0,8)."-".substr($one,8,4)."-".substr($one,12,4)."-".substr($one,16,4)."-".substr($one,20,4),);
			ksort($parms);
			$query = http_build_query($parms);
			$stringToSign = "GET&%2F&" . urlencode($query);
			$signature = urlencode(base64_encode(hash_hmac("sha1",$stringToSign,$accessKeysecret."&",true)));
			$queryStringWithSign = "Signature=". $signature ."&". $query;$tokenUrl = "http://nls-meta.cn-shanghai.aliyuncs.com/?".$queryStringWithSign;
			$token_string = $this->urlOpen($tokenUrl);
			$token_object = json_decode($token_string,true);

			$token = $token_object['Token']['Id'];
			$ExpireTime = $token_object['Token']["ExpireTime"] - time();
			Cache::set($accesskeyid,$token,$ExpireTime);
		}
		
		return $token;
	}
	public function urlOpen($url,$data = null,$header =null){
		$ch =curl_init();
		curl_setopt($ch,CURLOPT_URL,$url);
		//curl_setopt($ch,CURLOPT_HTTPHEADER,$header);
		//curl_setopt($ch,CURLOPT_USERAGENT,$url,$ua);
		if($data){
			curl_setopt($ch,CURLOPT_POST,1);
			curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
		}
		curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
		curl_setopt($ch,CURLOPT_REFERER,$url);
		curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
		curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
		$content = curl_exec($ch);
		$error = curl_error($ch);
		if($error){die($error);}
		curl_close($ch);
		return $content;
	}


}